package com.hatao.androidclient.wxapi;

import java.security.MessageDigest;
import java.util.LinkedList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONObject;

import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;

import com.qianseit.westore.BaseDoFragment;
import com.beautymiracle.androidclient.R;
import com.qianseit.westore.Run;
import com.tencent.mm.sdk.constants.Build;
import com.tencent.mm.sdk.modelpay.PayReq;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.WXAPIFactory;

public class WXPayFragment extends BaseDoFragment {
	private String mAppId, mPackageValue, mTimeStamp;
	private String mNonceStr, mPaySign, mSignType, mTradeId;

	private static final String TAG = "MicroMsg.SDKSample.PayActivity";

	private IWXAPI api;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		api = WXAPIFactory.createWXAPI(mActivity, Constants.APP_ID);
		api.registerApp(Constants.APP_ID);
	}

	/**
	 * 请求微信支付
	 * 
	 * @param productArgs
	 */
	public boolean callWXPay(JSONObject data) {
		try {
			mAppId = data.optString("appId");
			mTradeId = data.optString("traceid");
			mPackageValue = data.optString("package");
			mTimeStamp = data.optString("timeStamp");
			mNonceStr = data.optString("nonceStr");
			mPaySign = data.optString("paySign");
			mSignType = data.optString("signType");

			if (!TextUtils.isEmpty(mAppId)
					&& api.getWXAppSupportAPI() >= Build.PAY_SUPPORTED_SDK_INT) {
				new GetAccessTokenTask().execute();
				return true;
			}
		} catch (Exception e) {
		}
		return false;
	}

	private class GetAccessTokenTask extends
			AsyncTask<Void, Void, GetAccessTokenResult> {
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			showLoadingDialog();
		}

		@Override
		protected void onPostExecute(GetAccessTokenResult result) {
			if (result.localRetCode == LocalRetCode.ERR_OK) {
				GetPrepayIdTask getPrepayId = new GetPrepayIdTask(
						result.accessToken);
				getPrepayId.execute();
			} else {
				Run.alert(mActivity, R.string.confirm_order_pay_failed);
				hideLoadingDialog_mt();
			}
		}

		@Override
		protected GetAccessTokenResult doInBackground(Void... params) {
			GetAccessTokenResult result = new GetAccessTokenResult();

			String url = String
					.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
							Constants.APP_ID, Constants.APP_SECRET);

			byte[] buf = Util.httpGet(url);
			if (buf == null || buf.length == 0) {
				result.localRetCode = LocalRetCode.ERR_HTTP;
				return result;
			}

			String content = new String(buf);
			result.parseFrom(content);
			return result;
		}
	}

	private class GetPrepayIdTask extends
			AsyncTask<Void, Void, GetPrepayIdResult> {
		private String accessToken;

		public GetPrepayIdTask(String accessToken) {
			this.accessToken = accessToken;
		}

		@Override
		protected void onPostExecute(GetPrepayIdResult result) {
			hideLoadingDialog_mt();
			if (result.localRetCode == LocalRetCode.ERR_OK) {
				sendPayReq(result);
			} else {
				Run.alert(mActivity, R.string.confirm_order_pay_failed);
			}
		}

		@Override
		protected GetPrepayIdResult doInBackground(Void... params) {
			String url = String.format(
					"https://api.weixin.qq.com/pay/genprepay?access_token=%s",
					accessToken);
			GetPrepayIdResult result = new GetPrepayIdResult();
			String signedArgs = genProductArgs();

			Run.log("entity:", signedArgs);
			byte[] buf = Util.httpPost(url, signedArgs);
			if (buf == null || buf.length == 0) {
				result.localRetCode = LocalRetCode.ERR_HTTP;
				return result;
			}

			String content = new String(buf);
			result.parseFrom(content);
			return result;
		}
	}

	private static enum LocalRetCode {
		ERR_OK, ERR_HTTP, ERR_JSON, ERR_OTHER
	}

	private String genSign(List<NameValuePair> params) {
		StringBuilder sb = new StringBuilder();

		int i = 0;
		for (; i < params.size() - 1; i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append(params.get(i).getName());
		sb.append('=');
		sb.append(params.get(i).getValue());

		String sha1 = Util.sha1(sb.toString());
		return sha1;
	}

	private static class GetAccessTokenResult {
		private static final String TAG = "MicroMsg.SDKSample.PayActivity.GetAccessTokenResult";

		public LocalRetCode localRetCode = LocalRetCode.ERR_OTHER;
		public String accessToken;
		public int expiresIn;
		public int errCode;
		public String errMsg;

		public void parseFrom(String content) {

			if (content == null || content.length() <= 0) {
				Log.e(TAG, "parseFrom fail, content is null");
				localRetCode = LocalRetCode.ERR_JSON;
				return;
			}

			try {
				JSONObject json = new JSONObject(content);
				if (json.has("access_token")) { // success case
					accessToken = json.getString("access_token");
					expiresIn = json.getInt("expires_in");
					localRetCode = LocalRetCode.ERR_OK;
				} else {
					errCode = json.getInt("errcode");
					errMsg = json.getString("errmsg");
					localRetCode = LocalRetCode.ERR_JSON;
				}

			} catch (Exception e) {
				localRetCode = LocalRetCode.ERR_JSON;
			}
		}
	}

	private static class GetPrepayIdResult {
		private static final String TAG = "MicroMsg.SDKSample.PayActivity.GetPrepayIdResult";

		public LocalRetCode localRetCode = LocalRetCode.ERR_OTHER;
		public String prepayId;
		public int errCode;
		public String errMsg;

		public void parseFrom(String content) {

			if (content == null || content.length() <= 0) {
				Log.e(TAG, "parseFrom fail, content is null");
				localRetCode = LocalRetCode.ERR_JSON;
				return;
			}

			try {
				JSONObject json = new JSONObject(content);
				if (json.has("prepayid")) { // success case
					prepayId = json.getString("prepayid");
					localRetCode = LocalRetCode.ERR_OK;
				} else {
					localRetCode = LocalRetCode.ERR_JSON;
				}

				errCode = json.getInt("errcode");
				errMsg = json.getString("errmsg");

			} catch (Exception e) {
				localRetCode = LocalRetCode.ERR_JSON;
			}
		}
	}

	private String genProductArgs() {
		JSONObject json = new JSONObject();

		try {
			json.put("appid", mAppId);
			json.put("traceid", mTradeId);
			json.put("noncestr", mNonceStr);
			json.put("package", mPackageValue);
			json.put("timestamp", Long.parseLong(mTimeStamp));
			json.put("app_signature", mPaySign);
			json.put("sign_method", mSignType);
		} catch (Exception e) {
			return null;
		}

		return json.toString();
	}

	private void sendPayReq(GetPrepayIdResult result) {

		PayReq req = new PayReq();
		req.appId = mAppId;
		req.partnerId = Constants.PARTNER_ID;
		req.prepayId = result.prepayId;
		req.nonceStr = mNonceStr;
		req.timeStamp = mTimeStamp;
		req.packageValue = "Sign=" + mPackageValue;

		List<NameValuePair> signParams = new LinkedList<NameValuePair>();
		signParams.add(new BasicNameValuePair("appid", req.appId));
		signParams.add(new BasicNameValuePair("appkey", Constants.APP_KEY));
		signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
		signParams.add(new BasicNameValuePair("package", req.packageValue));
		signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
		signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
		signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));
		req.sign = genSign(signParams);

		// 在支付之前，如果应用没有注册到微信，应该先调用IWXMsg.registerApp将应用注册到微信
		Run.log("snedReq:", api.sendReq(req));
	}

	public static class MD5 {

		private MD5() {
		}

		public final static String getMessageDigest(byte[] buffer) {
			char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
					'9', 'a', 'b', 'c', 'd', 'e', 'f' };
			try {
				MessageDigest mdTemp = MessageDigest.getInstance("MD5");
				mdTemp.update(buffer);
				byte[] md = mdTemp.digest();
				int j = md.length;
				char str[] = new char[j * 2];
				int k = 0;
				for (int i = 0; i < j; i++) {
					byte byte0 = md[i];
					str[k++] = hexDigits[byte0 >>> 4 & 0xf];
					str[k++] = hexDigits[byte0 & 0xf];
				}
				return new String(str);
			} catch (Exception e) {
				return null;
			}
		}
	}
}